/**
 * API
 * 2018年9月25日
 * 创建bmp头数据
 */
#include <string.h>

typedef unsigned short FILETYPE;	//文件类型,Windows Bmp - "BM"

typedef struct
{
	unsigned int bfSize;			//整个文件的大小
	unsigned short bfReserved1;		//保留字
	unsigned short bfReserved2;		//保留字
	unsigned int bfOffBits;			//从文件开始到位图数据开始之间的数据(bitmap data)之间的偏移量
} BITMAPFILEHEADER;

typedef struct
{
	unsigned int biSize;			//本结构的大小40(28h)
	int biWidth;					//位图的宽度，以像素为单位
	int biHeight;					//位图的高度，以像素为单位
	unsigned short biPlanes;		//位图的为平面数,总为1
	unsigned short biBitCount;		//每像素所占bit数(8, 32,,,)
	unsigned int biCompression;		//压缩说明(BI_RGB, BI_RLE8, BI_RLE4) 0不压缩
	unsigned int biSizeImage;		//说明图像的大小，以字节为单位。当用BI_RGB格式时，可设置为0
	int biXPelsPerMeter;			//说明水平分辨率，用像素/米表示
	int biYPelsPerMeter;			//说明垂直分辨率，用像素/米表示
	unsigned int biClrUsed;			//说明位图使用的彩色表中的颜色索引数
	unsigned int biClrImportant;	//说明对图像显示有重要影响的颜色索引的数目，0表示都重要
} BITMAPINFOHEADER;

typedef struct
{
	unsigned char rgbBlue;        	//该颜色的蓝色分量
	unsigned char rgbGreen;       	//该颜色的绿色分量
	unsigned char rgbRed;         	//该颜色的红色分量
	unsigned char rgbReserved;    	//保留值
} RGBQUAD;

//*************************************************
// Method: 创建一个bmp头数据  
// FullName:  CreateBmpHead
// return: 						- 头大小(54或1078)
// Parameter: void *headData	- 头数据
// Parameter: int width			- 图像宽
// Parameter: int height		- 图像高
// Parameter: int bitCount 		- 每像素所占bit数
//*************************************************
int CreateBmpHead(char *headData, int nWidth, int nHeight, int bitCount)
{
	int headSize = 0;

	//文件格式
	FILETYPE fileType = 0x4D42;
	memcpy(headData + headSize, &fileType, sizeof(FILETYPE));
	headSize += sizeof(FILETYPE);

	//位图文件头
	unsigned int len = sizeof(FILETYPE)+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
	unsigned int rgbquadsize;
	if (bitCount == 8)
	{
		rgbquadsize = 256 * sizeof(RGBQUAD);
	}
	else
	{
		rgbquadsize = 0;
	}
	BITMAPFILEHEADER bmpFileHeader = { 0 };
	bmpFileHeader.bfSize = len + rgbquadsize + nWidth * nHeight * (bitCount / 8);
	bmpFileHeader.bfReserved1 = 0;
	bmpFileHeader.bfReserved2 = 0;
	bmpFileHeader.bfOffBits = len + rgbquadsize;
	memcpy(headData + headSize, &bmpFileHeader, sizeof(BITMAPFILEHEADER));
	headSize += sizeof(BITMAPFILEHEADER);

	//位图信息头
	BITMAPINFOHEADER bmpInfoHeader = { 0 };
	bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmpInfoHeader.biWidth = nWidth;
	bmpInfoHeader.biHeight = nHeight;
	bmpInfoHeader.biPlanes = 1;
	bmpInfoHeader.biBitCount = bitCount;
	bmpInfoHeader.biCompression = 0;
	int step = (nWidth % 4 == 0) ? nWidth : (nWidth + 4 - nWidth % 4);
	bmpInfoHeader.biSizeImage = nHeight*step;
	bmpInfoHeader.biXPelsPerMeter = 0;
	bmpInfoHeader.biYPelsPerMeter = 0;
	bmpInfoHeader.biClrUsed = 0;
	bmpInfoHeader.biClrImportant = 0;
	if (bitCount == 8)
	{
		bmpInfoHeader.biClrUsed = 256;
		bmpInfoHeader.biClrImportant = 256;
	}
	memcpy(headData + headSize, &bmpInfoHeader, sizeof(BITMAPINFOHEADER));
	headSize += sizeof(BITMAPINFOHEADER);

	//调色板 N*4
	if (bitCount == 8)
	{
		RGBQUAD quad[256 * sizeof(RGBQUAD)] = { 0 };
		int i;
		for (i = 0; i < 256; i++)
		{
			quad[i].rgbBlue = i;
			quad[i].rgbGreen = i;
			quad[i].rgbRed = i;
			quad[i].rgbReserved = 0;
		}
		memcpy(headData + headSize, quad, sizeof(RGBQUAD)* 256);
		headSize += sizeof(RGBQUAD)* 256;
	}

	return headSize;
}



////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>

//main test
int main(int argc, char const *argv[])
{
	// Define BMP Size
	int height = 240;
	int width = 320;
	char *bits = NULL;
	int x, len, size;
	char headData[1078];

	// Create Data
	memset(headData, 0x00, 54);
	len = CreateBmpHead(headData, width, height, 24);
	size = height * width * 3;
	bits = (char *)calloc(1, size);
	for (x = 0; x < size; x += 3)
	{
		bits[x + 0] = 0xFF;	// Blue
		bits[x + 1] = 0x00;	// Green
		bits[x + 2] = 0x00;	// Red
	}

	// Write To File
	FILE *fp1 = fopen("color.bmp", "wb");

	if (fp1 == NULL)
	{
		printf("Cannot open file!\n");
	}
	else
	{
		fwrite(headData, len, 1, fp1);
		fwrite(bits, size, 1, fp1);
		fclose(fp1);
	}

	free(bits);
	bits = NULL;

	////////////////////////////////////////////////////////////

	// Create Data
	memset(headData, 0x00, 1078);
	len = CreateBmpHead(headData, width, height, 8);
	size = height * width;
	bits = (char *)calloc(1, size);
	memset(bits, 0xF0, size);

	// Write To File
	FILE *fp2 = fopen("gray.bmp", "wb");

	if (fp2 == NULL)
	{
		printf("Cannot open file!\n");
	}
	else
	{
		fwrite(headData, len, 1, fp2);
		fwrite(bits, size, 1, fp2);
		fclose(fp2);
	}

	free(bits);
	bits = NULL;

	return 0;
}